#ifndef APPLICATION_H
#define APPLICATION_H

#include <cstdint>
#include <map>
#include <vector>

#include "ObjectPool.h"
#include "CarFactory.h"

class Client;
class Car;

class Application
{
public:
	static Application& instance() {
		static Application app(Application::m_initialPoolSize, Application::m_maxPoolSize);
		return app;
	}
	~Application();

	static void setInitialPoolSize(uint32_t initialPoolSize) { m_initialPoolSize = initialPoolSize; }
	static void setMaxPoolSize(uint32_t maxPoolSize) { m_maxPoolSize = maxPoolSize; }

	void run();

private:
	Application(uint32_t initialPoolSize, uint32_t poolSize);
	Application(Application const&);
	void operator=(Application const&);

private:
	void listCarsFunction();
	void addCarFunction();
	void removeCarFunction();

	void addCar(Client *owner, Car* car);
	void removeCar();

	Client* newClient();
	Client* getClientByName(std::string name);
	
	Car* getCarByName(Client *client, std::string name); 

	void printMenu();
	unsigned int readChoice();
	void handleChoice(unsigned int choice);
	unsigned int readInt();
	const std::string readWord();

private:
	enum MenuOption {
		EXIT_OPTION = 0,
		LIST_CARS_OPTION,
		ADD_CAR_OPTION,
		REMOVE_CAR_OPTION,
		OPTIONS_NUM,
	};
	struct MenuEntry {
		MenuOption menuOption;
		std::string description;
	};
	static MenuEntry m_menuEntries[OPTIONS_NUM];

	static uint32_t m_initialPoolSize;
	static uint32_t m_maxPoolSize;

	CarFactory m_carFactory;
	ObjectPool<Client> m_clientPool;
	std::map<Client*, std::vector<Car*>> m_clientCarsMap;
};

#endif